package view;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import java.util.Queue;

import javax.swing.JPanel;

import model.Extra;
import model.KISpieler;
import model.Linie;
import model.Schritt;
import model.Spieler;
import model.Spielfeld;
import controller.Spiel;

public class GamePanel extends JPanel {
	private Spielfeld spielfeld;
	private Spieler[] spieler;
	private String infoString = "";
	private BufferedImage cacheImage;
	private Queue<Rectangle> dirtyRegions;

	public GamePanel() {
		setFocusable(true);
		setBackground(Color.BLACK);
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);

		Graphics2D g2 = (Graphics2D) g;

		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);

		if (spielfeld != null) {
			g2.drawImage(this.cacheImage, 0, 0, null);
		}

		g2.setColor(Color.WHITE);
		g2.setFont(getFont().deriveFont(144f).deriveFont(Font.BOLD));
		g2.drawString(this.infoString, (getWidth() - g2.getFontMetrics()
				.stringWidth(this.infoString)) / 2, getHeight() / 2);

		g2.translate(0, getHeight());
		g2.scale(1.0, -1.0);

		if (this.spieler == null)
			return;
		for (Spieler s : this.spieler) {
			Linie l = s.getLinie();
			g2.setColor(l.transform.circleColor);
			float width = l.width * l.transform.widthFaktor.getValue();
			g2.fill(new Ellipse2D.Float(l.getX() - width, l.getY() - width,
					width * 2, width * 2));

			if (l.transform.pointWinner.getValue() > 0.1) {
				Color farbe = s.getFarbe();
				g2.setColor(new Color(farbe.getRed(), farbe.getGreen(), farbe
						.getBlue(),
						(int) (l.transform.pointWinner.getValue() * 255)));
				g2.setStroke(new BasicStroke(2));
				g2.draw(new Ellipse2D.Float(l.getX() - width * 2, l.getY()
						- width * 2, width * 4, width * 4));
			}

			// Display a distanceMap of the KI
			// if (s instanceof KISpieler && !s.isTot()) {
			// KISpieler ki = (KISpieler) s;
			// Point[] distMap = ki.distanceMap;
			// if (distMap != null) {
			// Polygon polygon = new Polygon();
			// // Highlight the favourite direction
			// Polygon favPolygon = new Polygon();
			// for (int i = 0; i < distMap.length; i++) {
			// if (distMap[i] == ki.favoritePoint) {
			// favPolygon.addPoint(
			// (int) l.lastSchritt.getMiddleX(),
			// (int) l.lastSchritt.getMiddleY());
			// if (i > 0)
			// favPolygon.addPoint(distMap[i - 1].x,
			// distMap[i - 1].y);
			// favPolygon.addPoint(distMap[i].x, distMap[i].y);
			// if (i < distMap.length - 1)
			// favPolygon.addPoint(distMap[i + 1].x,
			// distMap[i + 1].y);
			// }
			// polygon.addPoint(distMap[i].x, distMap[i].y);
			// }
			// Color farbe = s.getFarbe();
			// g2.setColor(new Color(farbe.getRed(), farbe.getGreen(),
			// farbe.getBlue(), 50));
			// g2.fillPolygon(polygon);
			// g2.setColor(new Color(farbe.getRed(), farbe.getGreen(),
			// farbe.getBlue(), 150));
			// g2.fillPolygon(favPolygon);
			// }
			// }
		}

		synchronized (Spiel.CURRENT_SPIEL.extras) {
			for (Extra e : Spiel.CURRENT_SPIEL.extras) {
				e.paint(g2);
			}
		}
	}

	public void setSpieler(Spieler[] spieler) {
		this.spieler = spieler;
	}

	@Override
	public Dimension getPreferredSize() {
		return new Dimension(Spiel.GAME_WIDTH, Spiel.GAME_HEIGHT);
	}

	@Override
	public Dimension getMaximumSize() {
		return getPreferredSize();
	}

	public void setSpielfeld(Spielfeld feld) {
		this.spielfeld = feld;
		this.cacheImage = new BufferedImage(feld.getWidth(), feld.getHeight(),
				BufferedImage.TYPE_4BYTE_ABGR);
		this.dirtyRegions = new LinkedList<Rectangle>();
		this.addDirtyRegion(new Rectangle(0, 0, cacheImage.getWidth(),
				cacheImage.getHeight()));
	}

	public void addDirtyRegion(Rectangle rect) {
		this.dirtyRegions.add(rect);
	}

	public void repaintDirtyRegions() {
		if (!this.dirtyRegions.isEmpty()) {
			Graphics2D g2 = cacheImage.createGraphics();
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_ON);
			g2.translate(0, cacheImage.getHeight());
			g2.scale(1.0, -1.0);
			while (!this.dirtyRegions.isEmpty()) {
				Rectangle next = this.dirtyRegions.poll();
				g2.setColor(Color.BLACK);
				g2.fill(next);
				synchronized (spielfeld) {
					for (Schritt schritt : spielfeld.getSchritteInRect(next)) {
						float[][] coords = schritt.getCoords();
						for (int i = 0; i < coords.length; i++) {
							if (!next.contains(coords[i][0], coords[i][1]))
								continue;
						}

						g2.setColor(schritt.getColor());
						g2.fillPolygon(new int[] { (int) coords[0][0],
								(int) coords[1][0], (int) coords[3][0],
								(int) coords[2][0] }, new int[] {
								(int) coords[0][1], (int) coords[1][1],
								(int) coords[3][1], (int) coords[2][1] }, 4);
					}
				}
			}
			g2.dispose();
		}
	}

	public String getInfoString() {
		return infoString;
	}

	public void setInfoString(String timeString) {
		this.infoString = timeString;
	}
}